package com.ld.shieldsb.common.core.io.img;

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;

import com.ld.shieldsb.common.core.io.FileUtils;

import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;

/**
 * 
 * 新的图片操作工具类
 * 
 * @ClassName ImgUtil
 * @author <a href="mailto:donggongai@126.com" target="_blank">kevin</a>
 * @date 2016年8月25日 下午3:12:22
 *
 */
@Slf4j
public class ImageUtil {
    private ImageUtil() {
        throw new IllegalStateException("该类不可初始化");
    }

    private static final String IMAGE_ERROR = "图片格式不正确，path:{}";
    private static final String IMAGE_NOT_EXIST = "水印图片不存在：{}";

    /**
     * 获取图片格式
     * 
     * @param file
     *            图片文件
     * @return 图片格式
     */
    public static String getImageFormatName(File file) throws IOException {
        String formatName = null;
        try (ImageInputStream iis = ImageIO.createImageInputStream(file)) { // 自动关闭流
            Iterator<ImageReader> imageReader = ImageIO.getImageReaders(iis);
            if (imageReader.hasNext()) {
                ImageReader reader = imageReader.next();
                formatName = reader.getFormatName();
            }
            if (formatName != null) { // 转小写
                formatName = formatName.toLowerCase();
            }
        } catch (Exception e) {
            log.error("", e);
        }

        return formatName;
    }

    /**
     * 获取图片格式
     * 
     * @Title getImageFormatName
     * @author 吕凯
     * @date 2017年5月16日 下午4:23:16
     * @param in
     * @return
     * @throws IOException
     *             String
     */
    public static String getImageFormatName(InputStream in) throws IOException {
        String formatName = null;
        try (ImageInputStream iis = ImageIO.createImageInputStream(in)) { // 自动关闭流
            Iterator<ImageReader> imageReader = ImageIO.getImageReaders(iis);
            if (imageReader.hasNext()) {
                ImageReader reader = imageReader.next();
                formatName = reader.getFormatName();
            }
            if (formatName != null) { // 转小写
                formatName = formatName.toLowerCase();
            }
        } catch (Exception e) {
            log.error("", e);
        }

        return formatName;
    }

    /**
     * 检验图片格式
     * 
     * @Title isImage
     * @author 吕凯
     * @date 2017年5月16日 下午4:20:11
     * @param file
     * @return boolean
     */
    public static boolean isSupportImage(File file) {
        try {
            String formatName = getImageFormatName(file);
            IMAGE_FORMAT[] imageFormats = IMAGE_FORMAT.values();
            for (IMAGE_FORMAT format : imageFormats) {
                if (format.getValue().equals(formatName)) {
                    return true;
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
        return false;
    }

    /**
     * 
     * 检验是否是支持的图片格式
     * 
     * @Title isSupportImage
     * @author 吕凯
     * @date 2017年5月16日 下午4:24:27
     * @param in
     * @return boolean
     */
    public static boolean isSupportImage(final InputStream in) {
        return isSupportImage(in, null);
    }

    /**
     * 
     * 检验是否是支持的图片格式
     * 
     * @Title isSupportImage
     * @author 吕凯
     * @date 2017年5月17日 上午9:02:17
     * @param in
     * @param imageFormats
     *            支持的格式
     * @return boolean
     */
    public static boolean isSupportImage(final InputStream in, IMAGE_FORMAT[] imageFormats) {
        try {
            String formatName = getImageFormatName(in);
            if (imageFormats == null) {
                imageFormats = IMAGE_FORMAT.values();
            }
            for (IMAGE_FORMAT format : imageFormats) {
                if (format.getValue().equals(formatName)) {
                    return true;
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
        return false;
    }

    /**
     * 
     * 设置图片 高宽
     * 
     * @Title setImageSize
     * @param imageFile
     *            图片文件
     * @param width
     *            宽度
     * @param height
     *            高度
     * @return boolean
     */
    public static boolean setImageSize(File imageFile, int width, int height) {
        try {
            BufferedImage image = read(imageFile);
            if (image == null) {
                log.error(IMAGE_ERROR, imageFile.getAbsolutePath());
                return false;
            }
            String formatName = getImageFormatName(imageFile);
            return saveImage2File(imageFile, formatName, imageFile, width, height);
        } catch (Exception e) {
            log.error("", e);
            return false;
        }
    }

    /**
     * 注意所有的读取走该方法，不要直接读取
     * 
     * @Title read
     * @author 吕凯
     * @date 2017年5月18日 上午11:16:57
     * @param imageFile
     * @return
     * @throws IOException
     *             BufferedImage
     */
    public static BufferedImage read(File imageFile) throws IOException {
        BufferedImage image = null;
        try {
            image = ImageIO.read(imageFile); // CMYK模式的jpg图片读取会出错
        } catch (IOException e) {
            image = readJpeg(imageFile);
        }
        return image;
    }

    /**
     * 写入一个 JPG 图像
     * 
     * @param im
     *            图像对象
     * @param targetJpg
     *            目标输出 JPG 图像文件
     * @param quality
     *            质量 0.1f ~ 1.0f
     */
    public static void writeJpeg(RenderedImage im, Object targetJpg, float quality) {
        try {
            ImageWriter writer = ImageIO.getImageWritersBySuffix("jpg").next();
            ImageWriteParam param = writer.getDefaultWriteParam();
            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            param.setCompressionQuality(quality);
            ImageOutputStream os = ImageIO.createImageOutputStream(targetJpg);
            writer.setOutput(os);
            writer.write((IIOMetadata) null, new IIOImage(im, null, null), param);
            os.flush();
            os.close();
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 
     * 尝试读取JPEG文件的高级方法,可读取32位的jpeg文件
     * 
     * @Title readJpeg
     * @param imageFile
     *            图片文件
     * @return
     * @throws IOException
     *             BufferedImage
     */
    private static BufferedImage readJpeg(File imageFile) throws IOException {
        Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JPEG");
        ImageReader reader = null;
        while (readers.hasNext()) {
            reader = readers.next();
            if (reader.canReadRaster()) {
                break;
            }
        }
        if (reader != null) {

            try (ImageInputStream input = ImageIO.createImageInputStream(imageFile)) {
                reader.setInput(input);
                // Read the image raster
                Raster raster = reader.readRaster(0, null);
                BufferedImage image = createJPEG4(raster);
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                writeJpeg(image, out, 1);
                out.flush();
                return ImageIO.read(new ByteArrayInputStream(out.toByteArray()));
            } catch (Exception e) {
                log.error("", e);
            }
        }
        return null;
    }

    /**
     * 
     * Java的ImageIO无法处理4-component图像并且Java2D不能应用于AffineTransformOp,所以将栅格数据转换为RGB . <br>
     * Technique due to MArk Stephens. Free for any use.
     * 
     * @Title createJPEG4
     * @param raster
     * @return BufferedImage
     */
    private static BufferedImage createJPEG4(Raster raster) {
        int w = raster.getWidth();
        int h = raster.getHeight();
        byte[] rgb = new byte[w * h * 3];

        float[] yVs = raster.getSamples(0, 0, w, h, 0, (float[]) null);
        float[] cbVs = raster.getSamples(0, 0, w, h, 1, (float[]) null);
        float[] crVs = raster.getSamples(0, 0, w, h, 2, (float[]) null);
        float[] kVs = raster.getSamples(0, 0, w, h, 3, (float[]) null);

        for (int i = 0, imax = yVs.length, base = 0; i < imax; i++, base += 3) {
            float k = 220 - kVs[i];
            float y = 255 - yVs[i];
            float cb = 255 - cbVs[i];
            float cr = 255 - crVs[i];

            double val = y + 1.402 * (cr - 128) - k;
            val = (val - 128) * .65f + 128;
            rgb[base] = val < 0.0 ? (byte) 0 : getRebBtye(val); // 0xff 表示为二进制 11111111,即255

            val = y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128) - k;
            val = (val - 128) * .65f + 128;
            rgb[base + 1] = val < 0.0 ? (byte) 0 : getRebBtye(val);

            val = y + 1.772 * (cb - 128) - k;
            val = (val - 128) * .65f + 128;
            rgb[base + 2] = val < 0.0 ? (byte) 0 : getRebBtye(val);
        }

        raster = Raster.createInterleavedRaster(new DataBufferByte(rgb, rgb.length), w, h, w * 3, 3, new int[] { 0, 1, 2 }, null);

        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
        ColorModel cm = new ComponentColorModel(cs, false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
        return new BufferedImage(cm, (WritableRaster) raster, true, null);
    }

    /**
     * 获取rgb的byte值
     * 
     * @Title getRegBtye
     * @author 吕凯
     * @date 2021年5月6日 上午8:42:06
     * @param val
     * @return byte
     */

    private static byte getRebBtye(double val) {
        return val > 255.0 ? (byte) 0xff : (byte) (val + 0.5); // 0xff 表示为二进制 11111111,即255
    }

    /**
     * 
     * 设置图片的宽度
     * 
     * @Title setImageSize
     * @param imageFile
     *            图片文件
     * @param width
     *            宽度
     * @return boolean
     */
    public static boolean setImageSize(File imageFile, int width) {
        try {
            BufferedImage image = read(imageFile);
            if (image == null) {
                log.error(IMAGE_ERROR, imageFile.getAbsolutePath());
                return false;
            }
            int iw = image.getWidth();// 原始图象的宽度
            int ih = image.getHeight();// 原始图象的高度
            if (iw > width) { // 宽度超过进行缩放
                int height = ih * width / iw;
                String formatName = getImageFormatName(imageFile);
                return saveImage2File(imageFile, formatName, imageFile, width, height);
            } else { // 什么都不做
                return true;
            }
        } catch (Exception e) {
            log.error("", e);
            return false;
        }
    }

    /**
     * 根据限制长度等比例获取图片的宽高.
     * 
     * @title setImageSize
     * @author 张和祥
     * @date 2016年7月6日
     * @param imageFile
     *            图片文件
     * @param maxWidthHeight
     *            最大宽度长度，长宽都不能超过这个值，超过会等比例缩放
     * @return
     */
    public static BufferedImage setImageSizeByMaxLength(File imageFile, int maxWidthHeight) {
        try {
            BufferedImage image = read(imageFile);
            if (image == null) {
                log.error(IMAGE_ERROR, imageFile.getAbsolutePath());
                return null;
            }
            int iw = image.getWidth(); // 原始图象的宽度
            int ih = image.getHeight(); // 原始图象的高度
            int width = iw;// 处理后的宽度
            int height = ih; // 处理后的高度

            if (iw > maxWidthHeight) { // 如果宽度大于指定长度，等比例缩放图片宽度
                width = maxWidthHeight;
                height = ih * maxWidthHeight / iw;
            }
            if (height > maxWidthHeight) {
                width = width * maxWidthHeight / height;
                height = maxWidthHeight;
            }

            // 获取宽高时使用newImg.getWidth()和newImg.getHeight()
            return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        } catch (Exception e) {
            log.error("", e);
            return null;
        }
    }

    /**
     * 
     * 图片保存成文件
     * 
     * @Title saveImage2File
     * @param File
     *            图片
     * @param saveImageFile
     *            文件
     * @param width
     *            宽度
     * @param height
     *            高度
     * @return boolean
     */
    public static boolean saveImage2File(File image, String formatName, File saveImageFile, int width, int height) {
        if (image == null) {
            return false;
        }
        try {
            resize(image, formatName, saveImageFile, width, height);
            return true;
        } catch (Exception e) {
            log.error("", e);
            return false;
        }
    }

    /**
     * 重新生成按指定宽度和高度的图像
     * 
     * @param File
     *            源图像文件
     * @param saveImageFile
     *            新的图像文件
     * @param width
     *            设置新的图像宽度
     * @param height
     *            设置新的图像高度
     */
    public static void resize(File image, String formatName, File saveImageFile, int width, int height) {
        resize(image, formatName, saveImageFile.getAbsolutePath(), width, height, 0, 0);
    }

    public static void resize(File image, File saveImageFile, int width, int height) throws IOException {
        String formatName = getImageFormatName(image);
        resize(image, formatName, saveImageFile.getAbsolutePath(), width, height, 0, 0);
    }

    public static void resize(File image, String formatName, String saveImagePath, int width, int height) {
        resize(image, formatName, saveImagePath, width, height, 0, 0);
    }

    public static void resize(File image, String saveImagePath, int width, int height) throws IOException {
        String formatName = getImageFormatName(image);
        resize(image, formatName, saveImagePath, width, height, 0, 0);
    }

    /**
     * 传入文件缩放，因为gif格式出入image有问题
     * 
     * @Title resize
     * @author 吕凯
     * @date 2017年5月16日 下午6:20:10
     * @param srcFile
     *            源文件
     * @param formatName
     *            文件后缀
     * @param saveImagePath
     *            保存路径
     * @param width
     *            宽度
     * @param height
     *            高度
     * @param x
     *            绘制开始x坐标
     * @param y
     *            绘制开始y坐标 void
     */
    public static void resize(File srcFile, String formatName, String saveImagePath, int width, int height, int x, int y) {
        try {
            BufferedImage src = read(srcFile);
            if (src == null) {
                log.error("图片读取失败！");
                return;
            }

            if (IMAGE_FORMAT.GIF.getValue().equals(formatName)) {// gif 特殊处理
                GifUtil.resize(srcFile, new File(saveImagePath), width, height);
                return;
            }

            Thumbnails.of(srcFile).size(width, height).toFile(new File(saveImagePath)); // 输出到文件流
        } catch (Exception e) {
            log.error("", e);
        }
    }

    /**
     * 添加水印文件右下角用于编辑器上传
     * 
     * @param imageFile
     *            上传文件
     * @param markFile
     *            水印文件，没有可为空
     * @param markDir
     *            生成新文件路径
     * @param maxWidth
     *            最大宽度（不超过时会使用自身宽度，超过会等比例缩放）
     * @return
     */
    public static File setWaterMarkRightBottom(File imageFile, File markFile, String newImgDir, Integer maxWidth) {
        return setWaterMarkRightBottom(imageFile, markFile, newImgDir, 1f, maxWidth); // 默认不透明

    }

    public static File setWaterMarkRightBottom(File imageFile, File markFile, String newImgDir) {
        return setWaterMarkRightBottom(imageFile, markFile, newImgDir, 1f, null); // 默认宽高

    }

    public static File setWaterMarkRightBottom(File imageFile, File markFile, String newImgDir, WaterMaskSettings settings) {
        return setWaterMarkRightBottom(imageFile, markFile, newImgDir, null, settings);
    }

    public static File setWaterMarkRightBottom(File imageFile, File markFile, String newImgDir, Integer maxWidth,
            WaterMaskSettings settings) {
        try {
            BufferedImage image = read(imageFile);
            if (image == null) {
                log.error(IMAGE_ERROR, imageFile.getAbsolutePath());
                return null;
            }
            int iw = image.getWidth();// 原始图象的宽度
            int ih = image.getHeight();// 原始图象的高度
            int height = ih;
            if (maxWidth != null && iw > maxWidth) {
                height = ih * maxWidth / iw;
            } else {
                maxWidth = iw;
            }
            return setWaterMarkRightBottom(imageFile, markFile, newImgDir, maxWidth, height, settings);
        } catch (IOException e) {
            log.error("", e);
            return null;
        }

    }

    /**
     * 
     * 添加水印文件右下角用于编辑器上传
     * 
     * @Title setWaterMarkRightBottom
     * @author 吕凯
     * @date 2021年5月6日 上午9:38:25
     * @param imageFile
     *            上传文件
     * @param markFile
     *            水印文件，没有可为空
     * @param newImgDir
     *            生成新文件路径
     * @param opacity
     *            水印透明度
     * @param maxWidth
     *            最大宽度（不超过时会使用自身宽度，超过会等比例缩放）
     * @return boolean
     */
    public static File setWaterMarkRightBottom(File imageFile, File markFile, String newImgDir, float opacity, Integer maxWidth) {
        WaterMaskSettings settings = WaterMaskSettings.builder().opacity(opacity).build();
        return setWaterMarkRightBottom(imageFile, markFile, newImgDir, maxWidth, settings);

    }

    /**
     * 添加水印文件用于编辑器上传(注意与后面的方法合并)
     * 
     * @param imageFile
     *            上传文件
     * @param markFile
     *            水印文件
     * @param newImgDir
     *            生成新文件路径
     * @param width
     *            输出宽度
     * @param height
     *            输出高度
     * @return
     */
    public static File setWaterMarkRightBottom(File imageFile, File markFile, String newImgDir, int width, int height,
            WaterMaskSettings settings) {
        try {
            settings = getBottomWaterMarkDefaultSettings(settings, width, height); // 设置底部水印的默认参数处理,注意此处进行了settings的初始化
            BufferedImage sourceBufferedImage = read(imageFile);
            if (sourceBufferedImage == null) {
                log.error(IMAGE_ERROR, imageFile.getAbsolutePath());
                return null;
            }
            BufferedImage newBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = newBufferedImage.createGraphics();
            Image image = sourceBufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            g.drawImage(image, 0, 0, width, height, null); // 重绘图片大小
            if (height > settings.getMinHeight()) { // 大于200才添加水印，这个参数可能需要处理
                // 水印文件
                if (checkWaterMarkImageExists(markFile)) {
                    g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, settings.getOpacity())); // 设置水印透明度

                    BufferedImage markImage = read(markFile);
                    if (markImage != null) {
                        getAndSetWaterMarkSettings(markImage, settings); // 参数处理
                        g.drawImage(markImage, settings.getDistanceX(), settings.getDistanceY(), settings.getWidth(), settings.getHeight(),
                                null);
                    }
                } else if (markFile != null && !markFile.exists()) {
                    log.warn(IMAGE_NOT_EXIST, markFile.getAbsolutePath());
                }
            }

            g.dispose();
            // 输出图像
            String fileName = imageFile.getName();
            File markImg = new File(newImgDir);
            if (!markImg.exists()) {
                markImg.mkdirs(); // 目录不存在则创建
            }
            File file = new File(newImgDir, fileName);
            ImageIO.write(newBufferedImage, "JPEG", file); // 写到新的位置
            return file;
        } catch (Exception e) {
            log.error("", e);
        }
        return null;
    }

    /**
     * 获取水印参数
     * 
     * @Title getWaterMarkWidthHeight
     * @author 吕凯
     * @date 2021年5月6日 上午10:11:04
     * @param markImage
     *            图片文件
     * @param settings
     *            设置信息
     * @return WaterMaskSettings
     */
    public static WaterMaskSettings getAndSetWaterMarkSettings(BufferedImage markImage, WaterMaskSettings settings) {
        int distanceX = settings.getDistanceX() == null ? 0 : settings.getDistanceX();
        int distanceY = settings.getDistanceY() == null ? 0 : settings.getDistanceY();
        int widthBiao = settings.getWidth() == null ? markImage.getWidth() : settings.getWidth();
        int heightBiao = settings.getHeight() == null ? markImage.getHeight() : settings.getHeight();
        settings.setDistanceX(distanceX);
        settings.setDistanceY(distanceY);
        settings.setWidth(widthBiao);
        settings.setHeight(heightBiao);
        return settings;
    }

    public static File setWaterMarkRightBottom(File imageFile, File markFile, String newImgDir, float opacity, int width, int height) {
        WaterMaskSettings settings = WaterMaskSettings.builder().opacity(opacity).build();
        getBottomWaterMarkDefaultSettings(settings, width, height);
        return setWaterMarkRightBottom(imageFile, markFile, newImgDir, width, height, settings);
    }

    /**
     * 获取底部水印的默认配置
     * 
     * @Title getBottomWaterMarkDefaultSettings
     * @author 吕凯
     * @date 2021年5月6日 上午11:06:18
     * @param settings
     * @param width
     * @param height
     * @return WaterMaskSettings
     */
    private static WaterMaskSettings getBottomWaterMarkDefaultSettings(WaterMaskSettings settings, int width, int height) {
        if (settings == null) {
            settings = WaterMaskSettings.builder().build();
        }
        int distanceX = settings.getDistanceX() == null ? width - 150 : settings.getDistanceX();
        int distanceY = settings.getDistanceY() == null ? height - 42 : settings.getDistanceY();
        int minHeight = settings.getMinHeight() == null ? 200 : settings.getMinHeight();
        settings.setDistanceX(distanceX);
        settings.setDistanceY(distanceY);
        settings.setMinHeight(minHeight);
        return settings;
    }

    /**
     * 添加水印文件用于编辑器上传(注意与后面的方法合并)
     * 
     * @param imageFile
     *            上传文件
     * @param markFile
     *            水印文件，没有可为空
     * @param newImgDir
     *            生成新文件路径
     * @param opacity
     *            水印透明度
     * @param maxWidth
     *            输出宽度（高度会等比例缩放）
     * @return
     */
    public static File setWaterMark(File imageFile, File markFile, String newImgDir, Integer maxWidth) {
        return setWaterMark(imageFile, markFile, newImgDir, 1f, maxWidth, 250, 20);
    }

    /**
     * 添加水印文件，不设置最大宽度，不进行缩放
     * 
     * @Title setWaterMark
     * @author 吕凯
     * @date 2021年5月6日 上午11:34:52
     * @param imageFile
     * @param markFile
     * @param newImgDir
     * @return File
     */
    public static File setWaterMark(File imageFile, File markFile, String newImgDir) {
        return setWaterMark(imageFile, markFile, newImgDir, (Integer) null);
    }

    /**
     * 
     * 添加水印文件用于编辑器上传(注意与后面的方法合并)
     * 
     * @Title setWaterMark
     * @author 吕凯
     * @date 2019年6月20日 下午12:40:44
     * @param imageFile
     *            上传文件
     * @param markFile
     *            水印文件，没有可为空
     * @param newImgDir
     *            生成新文件路径
     * @param opacity
     *            水印透明度
     * @param maxWidth
     *            输出宽度（高度会等比例缩放）
     * @param distanceY
     *            x轴距离
     * @param distanceX
     *            y轴距离
     * @return File
     */
    public static File setWaterMark(File imageFile, File markFile, String newImgDir, float opacity, Integer maxWidth, int distanceY,
            int distanceX) {
        WaterMaskSettings settings = WaterMaskSettings.builder().opacity(opacity).distanceX(distanceX) // 上下距离
                .distanceY(distanceY) // 左右距离
                .build();
        return setWaterMark(imageFile, markFile, newImgDir, maxWidth, settings);

    }

    /**
     * 根据设置的水印信息添加水印文件
     * 
     * @Title setWaterMark
     * @author 吕凯
     * @date 2019年6月20日 下午3:06:14
     * @param imageFile
     *            源文件
     * @param markFile
     *            水印文件
     * @param newImgDir
     *            新图片的存放路径
     * @param width
     *            输出宽度（高度会等比例缩放）
     * @param settings
     *            水印信息
     * @return boolean
     */
    public static File setWaterMark(File imageFile, File markFile, String newImgDir, Integer maxWidth, WaterMaskSettings setting) {
        try {
            BufferedImage image = read(imageFile);
            if (image == null) {
                log.error(IMAGE_ERROR, imageFile.getAbsolutePath());
                return null;
            }
            int iw = image.getWidth();// 原始图象的宽度
            int ih = image.getHeight();// 原始图象的高度
            int height = ih;
            if (maxWidth != null && iw > maxWidth) { // 原图宽度大于设置的宽度则进行等比例缩放
                height = ih * maxWidth / iw;
            } else {
                maxWidth = iw;
            }
            return setWaterMark(imageFile, markFile, newImgDir, maxWidth, height, setting);
        } catch (IOException e) {
            log.error("", e);
            return null;
        }

    }

    public static File setWaterMark(File imageFile, File markFile, String newImgDir, WaterMaskSettings setting) {
        return setWaterMark(imageFile, markFile, newImgDir, null, setting);
    }

    public static File setWaterMark(File imageFile, File markFile, String newImgDir, float opacity, int width, int height) {
        WaterMaskSettings settings = WaterMaskSettings.builder().opacity(opacity).distanceX(250) // 上下距离
                .distanceY(20) // 左右距离
                .build();
        return setWaterMark(imageFile, markFile, newImgDir, width, height, settings);
    }

    /**
     * 添加水印文件用于编辑器上传(注意与后面的方法合并)
     * 
     * @param imageFile
     *            上传文件
     * @param markFile
     *            水印文件
     * @param newImgDir
     *            生成新文件路径
     * @param opacity
     *            水印透明度
     * @param width
     *            输出宽度
     * @param height
     *            输出高度
     * @return boolean
     * @return
     */

    public static File setWaterMark(File imageFile, File markFile, String newImgDir, int width, int height, WaterMaskSettings settings) {
        try {
            BufferedImage sourceBufferedImage = read(imageFile);
            if (sourceBufferedImage == null) {
                log.error(IMAGE_ERROR, imageFile.getAbsolutePath());
                return null;
            }
            // 构建新的图片
            BufferedImage newBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            String formatName = getImageFormatName(imageFile);
            Graphics2D g = newBufferedImage.createGraphics();
            if (formatName != null && formatName.equals("png")) {
                // 将原图放大或缩小后画下来:并且保持png图片放大或缩小后背景色是透明的而不是黑色
                newBufferedImage = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
                g.dispose();
                g = newBufferedImage.createGraphics();
            }
            Image image = sourceBufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            g.drawImage(image, 0, 0, width, height, null); // 重绘图片大小

            drawWaterMarkImage(markFile, width, height, settings, g); // 绘制水印文件

            g.dispose();
            // 输出图像
            String fileName = imageFile.getName();
            File markImg = new File(newImgDir);
            if (!markImg.exists()) {
                markImg.mkdirs(); // 目录不存在则创建
            }
            File drawFile = new File(newImgDir, fileName);
            ImageIO.write(newBufferedImage, formatName, drawFile); // 写到新的位置
            return drawFile;
        } catch (Exception e) {
            log.error("", e);
        }
        return null;
    }

    /**
     * 绘制水印文件
     * 
     * @Title drawWaterMarkImage
     * @author 吕凯
     * @date 2021年5月6日 上午8:57:03
     * @param markFile
     * @param width
     * @param height
     * @param settings
     * @param g
     * @throws IOException
     *             void
     */
    private static void drawWaterMarkImage(File markFile, int width, int height, WaterMaskSettings settings, Graphics2D g)
            throws IOException {
        settings = getWaterMarkDefaultSettings(settings); // 获取水印参数设置如果没有初始化则初始化
        if (height > settings.getMinHeight() && checkWaterMarkImageExists(markFile)) { // 大于200才添加水印
            // 水印文件
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, settings.getOpacity())); // 设置水印透明度

            BufferedImage markImage = read(markFile);
            if (markImage != null) {
                getAndSetWaterMarkSettings(markImage, settings); // 处理参数

                int widthMarkImage = settings.getWidth();
                int heightMarkImage = settings.getHeight();
                g.rotate(-Math.PI / 4); // 倾斜45度，以左上角为圆点旋转
                int distanceY = settings.getDistanceY(); // 上下间距
                int distanceX = settings.getDistanceX(); // 左右间距
                int markDrawWidth = widthMarkImage + distanceX;
                int markDrawHeight = heightMarkImage + distanceY;

                double bianchang = (height + width) / Math.sqrt(2);
                double roundY = bianchang / markDrawHeight; // 旋转45度则高度刚好是长+宽处以根号2
                double roundX = bianchang / markDrawWidth + 1;
                // 先绘制后旋转
                for (int i = 0; i < roundY; i++) { // y轴输出
                    for (int j = 0; j < roundX; j++) { // x轴输出，
                        // 以左上角为0点坐标，向右x向下y，10为距顶部高度,height / Math.sqrt(2)向左缩进的部分正好是height/根号2
                        g.drawImage(markImage, j * markDrawWidth - (int) (height / Math.sqrt(2)), i * markDrawHeight + 20, widthMarkImage,
                                heightMarkImage, null);
                    }
                }
            }
        }
    }

    /**
     * 设置多行斜水印的默认配置
     * 
     * @Title getWaterMarkDefaultSettings
     * @author 吕凯
     * @date 2021年5月6日 下午1:45:15
     * @param settings
     * @return WaterMaskSettings
     */
    private static WaterMaskSettings getWaterMarkDefaultSettings(WaterMaskSettings settings) {
        if (settings == null) {
            settings = WaterMaskSettings.builder().build();
        }
        int distanceX = settings.getDistanceX() == null ? 250 : settings.getDistanceX();
        int distanceY = settings.getDistanceY() == null ? 20 : settings.getDistanceY();
        int minHeight = settings.getMinHeight() == null ? 200 : settings.getMinHeight();
        settings.setDistanceX(distanceX);
        settings.setDistanceY(distanceY);
        settings.setMinHeight(minHeight);
        return settings;
    }

    /**
     * 检查水印文件是否存在
     * 
     * @Title checkWaterMarkImageExists
     * @author 吕凯
     * @date 2021年5月6日 上午9:00:23
     * @param markFile
     * @return boolean
     */
    private static boolean checkWaterMarkImageExists(File markFile) {
        if (markFile != null && markFile.exists()) {
            return true;
        } else if (markFile != null && !markFile.exists()) {
            log.warn(IMAGE_NOT_EXIST, markFile.getAbsolutePath());
        }
        return false;
    }

    /**
     * 添加水印文件(默认增加4行水印)
     * 
     * @param imageFile
     *            上传文件
     * @param markFile
     *            水印文件
     * @param newImgDir
     *            生成新文件路径
     * @param opacity
     *            水印透明度
     * @param width
     *            自定义图片宽度
     * @param height
     *            自定义图片高度
     * @return
     */
    public static boolean setWaterMarkBySize(File imageFile, File markFile, String newImgDir, float opacity, int width, int height) {
        try {
            BufferedImage sourceBufferedImage = read(imageFile);
            if (sourceBufferedImage == null) {
                log.error(IMAGE_ERROR, imageFile.getAbsolutePath());
                return false;
            }

            BufferedImage newBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = newBufferedImage.createGraphics();
            Image image = sourceBufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            g.drawImage(image, 0, 0, width, height, null); // 重绘图片大小
            // 水印文件
            if (checkWaterMarkImageExists(markFile)) {
                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, opacity)); // 设置水印透明度

                BufferedImage markImage = read(markFile);
                if (markImage != null) {

                    int widthMarkImage = markImage.getWidth();
                    int heightMarkImage = markImage.getHeight();
                    int heightmark = (int) (height + width * Math.sqrt(2) - 10);
                    g.rotate(-Math.PI / 4); // 倾斜45度
                    int distance = 150;
                    for (int i = 0; i < heightmark / distance; i++) { // 先绘制后旋转
                        for (int j = 0; j < 4; j++) {
                            // g.drawImage(markImage, j * 215 - 445, 360, width_biao,
                            // height_biao, null);
                            g.drawImage(markImage, j * 215 - 445, i * distance + 5, widthMarkImage, heightMarkImage, null);
                        }
                    }
                }
            } else if (markFile != null && !markFile.exists()) {
                log.warn(IMAGE_NOT_EXIST, markFile.getAbsolutePath());
            }

            g.dispose();
            // 输出图像
            String fileName = imageFile.getName();
            File markImg = new File(newImgDir);
            if (!markImg.exists()) {
                markImg.mkdirs();
            }
            ImageIO.write(newBufferedImage, "JPEG", new File(newImgDir, fileName));
            return true;
        } catch (Exception e) {
            log.error("", e);
        }
        return false;
    }

    /**
     * 生成小图片（100x100和50x50）
     * 
     * @Title createSmallPhoto
     * @author 吕凯
     * @date 2019年6月20日 上午8:58:39
     * @param imageFile
     * @param newImgDir
     * @return boolean
     */
    public static File createSmallPhoto(File imageFile, String newImgDir) {
        try {
            BufferedImage sourceBufferedImage = read(imageFile);
            if (sourceBufferedImage == null) {
                log.error(IMAGE_ERROR, imageFile.getAbsolutePath());
                return null;
            }
            int width = 100;
            int height = 100;

            // 输出图像
            String fileName = imageFile.getName();
            File markImg = new File(newImgDir);
            if (!markImg.exists()) {
                markImg.mkdirs();
            }
            String formatName = getImageFormatName(imageFile);
            resize(imageFile, formatName, new File(newImgDir, fileName + ""), width, height); // 正常处理png、gif等

            String fileNameWithoutExtension = FileUtils.getFileNameWithoutExtension(fileName);
            String fileExtension = FileUtils.getFileExtension(fileName);
            File smallFile = new File(newImgDir, fileNameWithoutExtension + "_min." + fileExtension);
            saveImage2File(imageFile, formatName, smallFile, 50, 50);
            return smallFile;
        } catch (Exception e) {
            log.error("", e);
        }
        return null;
    }

    /**
     * 图片旋转
     * 
     * @Title rotateImg
     * @author 吕凯
     * @date 2019年6月20日 上午8:57:57
     * @param imageFile
     *            图片路径
     * @param degree
     *            旋转角度
     * @return boolean
     */
    public static boolean rotateImg(File imageFile, int degree) {
        try {
            BufferedImage image = read(imageFile);
            if (image != null) {
                String formatName = getImageFormatName(imageFile);
                BufferedImage rotatedImage = rotateImage(image, degree);
                ImageIO.write(rotatedImage, formatName, imageFile);
                return true;
            }
        } catch (IOException e) {
            log.error("图片旋转失败", e);
        }
        return false;
    }

    public static BufferedImage rotateImage(BufferedImage bufferedImage, int angel) throws IOException {
        if (bufferedImage != null) {

            int imageWidth = bufferedImage.getWidth();// 原始图象的宽度
            int imageHeight = bufferedImage.getHeight();// 原始图象的高度

            angel = angel % 360; // 取余，360为一圈
            if (angel < 0) {
                angel = 360 + angel;// 将角度转换到0-360度之间，负数表示逆时针旋转
            }
            // 计算重新绘制图片的尺寸，直接处理在角度为非90的倍数时会有锯齿，所以使用第三方工具类处理
            return Thumbnails.of(bufferedImage).size(imageWidth, imageHeight).rotate(angel).asBufferedImage();
        }
        return null;
    }

    /**
     * 校验图片固定大小 长宽必须为参数值
     * 
     * @title checkFixedSize
     * @author 张和祥
     * @date 2017年3月24日
     */
    public static boolean checkFixedSize(File imageFile, int width, int height) {
        try {
            BufferedImage sourceBufferedImage = read(imageFile);
            if (sourceBufferedImage == null) {
                log.error(IMAGE_ERROR, imageFile.getAbsolutePath());
                return false;
            }
            int imgWidth = sourceBufferedImage.getWidth(); // 上传图片宽度
            int imgHeight = sourceBufferedImage.getHeight(); // 上传图片高度
            if (imgWidth == width && imgHeight == height) {
                return true;
            }
        } catch (Exception e) {
            log.error("", e);
        }
        return false;
    }

    /**
     * 获取不包含后缀的文件路径
     * 
     * @param src
     * @return
     */
    public static String getPathWithoutSuffix(String src) {
        String path = src;
        int index = path.lastIndexOf('.');
        if (index > 0) {
            path = path.substring(0, index);
        }
        return path;
    }

    /**
     * 获取真实后缀的路径，防止图片后缀与图片本身类型不一致的情况
     * 
     * @Title getRealSuffixPath
     * @author 吕凯
     * @date 2017年5月18日 上午9:40:00
     * @param src
     *            图片路径
     * @param formatName
     *            真实后缀，建议通过getImageFormatName方法获取传入
     * @return String
     */
    public static String getRealSuffixPath(String src, String formatName) {
        if (formatName == null) {
            try {
                formatName = getImageFormatName(new File(src));
            } catch (Exception e) {
                log.error("获取文件后缀出错", e);
            }
        }
        String pathPrefix = getPathWithoutSuffix(src);
        return pathPrefix + '.' + formatName;
    }

    /**
     * 
     * 获取真实后缀的路径，防止图片后缀与图片本身类型不一致的情况
     * 
     * @Title getRealSuffixPath
     * @author 吕凯
     * @date 2017年5月18日 上午9:43:34
     * @param src
     *            图片路径
     * @return String
     */
    public static String getRealSuffixPath(String src) {
        return getRealSuffixPath(src, null);
    }

    /**
     * 图像裁剪
     * 
     * @param srcImageFilePath
     *            源图像地址
     * @param dirImageFilePath
     *            新图像地址
     * @param x
     *            目标切片起点x坐标
     * @param y
     *            目标切片起点y坐标
     * @param destWidth
     *            目标切片宽度
     * @param destHeight
     *            目标切片高度
     */
    public static void crop(String srcImageFilePath, String dirImageFilePath, int x, int y, int destWidth, int destHeight) {
        File srcFile = new File(srcImageFilePath);
        crop(srcFile, new File(dirImageFilePath), x, y, destWidth, destHeight);

    }

    /**
     * 图片裁剪
     * 
     * @Title crop
     * @author 吕凯
     * @date 2021年8月12日 下午2:57:53
     * @param srcImageFile
     * @param dirImageFile
     * @param x
     *            裁剪开始x坐标
     * @param y
     *            裁剪开始y坐标
     * @param destWidth
     * @param destHeight
     *            void
     */
    public static void crop(File srcImageFile, File dirImageFile, int x, int y, int destWidth, int destHeight) {
        try {
            // 读取源图像
            String formatName = getImageFormatName(srcImageFile);

            if (IMAGE_FORMAT.GIF.getValue().equals(formatName)) {// gif
                GifUtil.crop(srcImageFile, dirImageFile, x, y, destWidth, destHeight);
                return;
            }

            Thumbnails.of(srcImageFile).sourceRegion(x, y, destWidth, destHeight).size(destWidth, destHeight).toFile(dirImageFile);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 彩色转为黑白
     * 
     * @param sourcePath
     *            原路径
     * @param resultPath
     *            输出路径
     */
    public static void gray(String sourcePath, String resultPath) {
        gray(new File(sourcePath), new File(resultPath));
    }

    /**
     * 转为黑白图片
     * 
     * @Title gray
     * @author 吕凯
     * @date 2021年8月12日 下午3:09:53
     * @param sourceFile
     * @param resultFile
     *            void
     */
    public static void gray(File sourceFile, File resultFile) {
        try {
            String formatName = getImageFormatName(sourceFile);
            BufferedImage src = ImageIO.read(sourceFile);
            ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
            ColorConvertOp op = new ColorConvertOp(cs, null);
            src = op.filter(src, null);
            ImageIO.write(src, formatName, resultFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
